package guiclient;

import guicommon.Message;
import guicommon.controls.Button;
import guicommon.controls.Control;
import guicommon.controls.Window;
import guicommon.controls.handlers.EventArgs;
import guicommon.controls.handlers.EventMessage;
import guicommon.controls.handlers.MouseClickedEventHandler;
import guicommon.controls.handlers.MouseEventArgs;
import guicommon.gui.ControlMessage;
import guicommon.gui.EmptyControlMessage;
import guicommon.gui.UpdateMessage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class Application {

    private ArrayList<Control> controls;

    private Queue<ControlMessage> controlsMessages;

    private ConcurrentLinkedQueue<UpdateMessage> updatesMassages;

    private Hashtable<ControlMessage, Control> mapMsgToControl;

    private Hashtable<String, Control> mapIdToControl;

    private Client myClient;

    private boolean isOpened = false;

    private ConcurrentLinkedQueue<Control> lastSendedControl;
    
    protected Application() throws IOException {
        controlsMessages = new LinkedList();
        controls = new ArrayList();
        myClient = new Client(this);
        mapMsgToControl = new Hashtable();
        mapIdToControl = new Hashtable();
        updatesMassages = new ConcurrentLinkedQueue();
        lastSendedControl = new ConcurrentLinkedQueue();
    }

    public void Show() {
        myClient.Start();
        isOpened = true;
    }

    protected void RegisterWindow(Window window) {
        RegisterControl(window);
        Button closeButton = window.GetCloseButton();
        closeButton.SetPoint(closeButton.GetX() + window.GetWidth(), closeButton.GetY());
        closeButton.SetMouseClickedEventHandler(new MouseClickedEventHandler() {

            @Override
            public void Event(Control sender, MouseEventArgs args) {
                Close();
            }
        });
        closeButton.SetOwner(window);
        RegisterControl(closeButton);
    }
    
    protected void RegisterControl(Control control) {
        controls.add(control);
        ControlMessage msg = control.ToMessage();
        controlsMessages.add(msg);
        mapMsgToControl.put(msg, control);
    }

    public ControlMessage GetNextControlMessage() {
        if (controlsMessages.isEmpty()) {
            return new EmptyControlMessage();
        }
        ControlMessage result = controlsMessages.remove();
        lastSendedControl.add(mapMsgToControl.get(result));
        mapMsgToControl.remove(result);
        return result;
    }

    void SetIdToLastSendedControl(String id) {
        Control lastSendedControl = this.lastSendedControl.poll();
        mapIdToControl.put(id, lastSendedControl);
        lastSendedControl.SubscribeOnUpdate(id, updatesMassages);
    }

    Message GetNextHandlerMessage(EventMessage eventMessage) {
        String id = eventMessage.GetSender();
        if (mapIdToControl.containsKey(id)) {
            Control control = mapIdToControl.get(id);
            EventArgs evtArgs = EventArgs.EventArgsFactory(eventMessage.GetEventArgs());
            if (evtArgs != null) {
                control.HandleEvent(evtArgs);
            }
        } 
        return new EmptyControlMessage();
    }

    public void Close() {
        myClient.Close();
        isOpened = false;
    }

    UpdateMessage GetNextUpdateMessage() {
        if (updatesMassages.isEmpty()) {
            return null;
        }
        return updatesMassages.poll();
    }

    protected void SendUpdateMessage(String id, String key, String value) {
        UpdateMessage update = new UpdateMessage();
        update.SetUpdatedField(id, key, value);
        updatesMassages.add(update);
    }

    public boolean IsNotClose() {
        return isOpened;
    }
}
